#include "interfaz_fuse.h"


/*____________________________________________________*/

int FS_create(const char *rutaArchivo, mode_t modoApertura, struct fuse_file_info *fi){


	(void)fi;
	int resultado;
	datosArchivo*data=NULL;
	data=malloc(sizeof(datosArchivo));
	data->tipo=ARCHIVO;
	data->tamanioArchivo=0;
	
	char*ruta=malloc(strlen(rutaArchivo)+1);
	
	strncpy(ruta,rutaArchivo,strlen(rutaArchivo));
	ruta[strlen(rutaArchivo)]='\0';
	
	resultado=buscarArchivo(ruta,data);
	if(resultado!=0){
		resultado=crearArchivoDirectorio(ruta,data,modoApertura,0);
		buscarArchivo(ruta,data);
		data->lista=NULL;
		data->lista=malloc(sizeof(listaClusters));
		data->lista->numCluster=0;
		data->cantClusters=0;
		//conseguirCadenaClusters(data->lista,data->numCluster);
	//	if(tamanioCache!=0&&cantLugares!=0){

	//		data->cacheArchivo=inicializarCache(ruta);
		//}
		fi->fh= (long)data;
		free(ruta);
		return resultado;
	}
	else{
		data->lista=NULL;
		data->lista=malloc(sizeof(listaClusters));
		data->lista->numCluster=0;
		if(data->numCluster!=0)
		data->cantClusters=conseguirCadenaClusters(data->lista,data->numCluster);
		fi->fh= (long)data;
		free(ruta);
	}
	return 0;
}

/*____________________________________________________*/

int FS_open(const char *rutaArchivo, struct fuse_file_info *infoArchivo){

	(void)infoArchivo;
	int resultado=0;
	datosArchivo* data=NULL;
	data=malloc(sizeof(datosArchivo));
	char*ruta=malloc(strlen(rutaArchivo)+1);
	strncpy(ruta,rutaArchivo,strlen(rutaArchivo));
	ruta[strlen(rutaArchivo)]='\0';
	
	resultado=buscarArchivo(ruta,data);
	if(resultado!=0){
	//	free(ruta);
	//	free(data);
		return (-ENOENT);
	}
	else{
		data->lista=NULL;
		data->lista=malloc(sizeof(listaClusters));
		data->lista->numCluster=0;
		if(data->numCluster!=0){
			data->cantClusters=		conseguirCadenaClusters(data->lista,data->numCluster);

		listaClusters *ptr=data->lista;
		while(ptr!=NULL){
			printf("%i\n",ptr->numCluster);
			ptr=ptr->sig;
		}
		}
		else
			data->cantClusters=0;
		if(tamanioCache!=0&&cantLugares!=0){

					data->cacheArchivo=inicializarCache(ruta);
				}
		infoArchivo->fh= (long)data;
	//	free(ruta);
		return 0;
	}
}

/*____________________________________________________*/

int FS_read(const char *rutaArchivo, char *buffer, size_t tamanio, off_t offset, struct fuse_file_info* fi){

	datosArchivo* data;
	int resultado;
	data=malloc(sizeof(datosArchivo));
	down(sem);
	int inter =(long)(fi->fh);
	data= (datosArchivo*)inter;
	up(sem);
	if ((tamanio + (int) offset) > data->tamanioArchivo)
		tamanio = (data->tamanioArchivo - offset);
	down(sem);
	resultado=leerDatos(data,buffer,offset,tamanio);
	//data->resultadoOper=resultado;
	fi->fh= (long)data;
	up(sem);
	printf("TAMM %i\n",tamanio);
	if(resultado < 0)
			return resultado;
		else if(resultado >= tamanio){
			buffer[tamanio]='\0';
			return tamanio;
		}
		else{
			buffer[resultado]='\0';
			return resultado;
	}
}

/*____________________________________________________*/

int FS_write(const char *rutaArchivo, const char *buffer, size_t tamanio, off_t offset, struct fuse_file_info *fi){
	datosArchivo* data;
	int resultado;
	
	data=malloc(sizeof(datosArchivo));
	down(sem);
	data= (datosArchivo*)(long)fi->fh;
	up(sem);
	char*ruta=malloc(strlen(rutaArchivo)+1);
	
	strncpy(ruta,rutaArchivo,strlen(rutaArchivo));
	ruta[strlen(rutaArchivo)]='\0';

	if(data->numCluster==0){
		int numCluster=0;
		down(mutexFAT);
		if(numClustersLibres>=1){
			up(mutexFAT);

		int rIO= buscar_Clusters_libres(1,&numCluster);

		if(rIO!=0){
			return -EIO;
		}
		else{
			data->numCluster=numCluster;
			grabar_FAT(data->numCluster,0xFFFFFFF);
		}
	}
				 else{
					 up(mutexFAT);
					 return -ENOSPC;
				 }

		char bufferEscritura[1024];

		realizar_pedido_lectura(data->sectorEntrada/2,bufferEscritura);
		if(data->sectorEntrada>data->sectorEntrada/2+data->sectorEntrada/2)
			data->offset+=512;
		if(data->longfn==1){
			char vecAux[4];

			memset(vecAux,0,4);

			memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
			memcpy(bufferEscritura+data->offset+32+0x1A,vecAux,sizeof(uint16_t));
			memcpy(bufferEscritura+data->offset+32+0x14,vecAux+2,sizeof(uint16_t));

		}
		else{
			char vecAux[4];

			memset(vecAux,0,4);

			memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
			memcpy(bufferEscritura+data->offset+0x1A,vecAux,sizeof(uint16_t));
			memcpy(bufferEscritura+data->offset+0x14,vecAux+2,sizeof(uint16_t));

					  			}
			realizar_pedido_escritura(data->sectorEntrada/2,bufferEscritura);
			int clus=data->numCluster;
			agregarCluster(&clus,data->lista);
data->cantClusters=1;
	}
	down(sem);
	resultado=escribirArchivo(ruta,data,buffer,offset,tamanio);
	//data->resultadoOper=resultado;
	//
	fi->fh= (long)data;
	up(sem);
	printf("TAMM %i\n",tamanio);
	if(resultado < 0){
			free(ruta);
				return resultado;
		}
			else if (resultado>tamanio){
				free(ruta);
				return tamanio;
			}
			else{
				free(ruta);
				return resultado;
			}
	}


/*____________________________________________________*/

int FS_flush(const char *rutaArchivo, struct fuse_file_info *fi){
	datosArchivo* data;
	data=malloc(sizeof(datosArchivo));
down(sem);
	data= (datosArchivo*)(long)fi->fh;
up(sem);
	if(tamanioCache>0){
		int tam;
				for(tam=0;tam<cantLugares&&data->cacheArchivo.contCache[tam].sector!=(-1);tam++){
					if(data->cacheArchivo.contCache[tam].modificado==1)
						realizar_pedido_escritura(data->cacheArchivo.contCache[tam].sector,data->cacheArchivo.contCache[tam].contenido);
					data->cacheArchivo.contCache[tam].sector=-1;
					memset(data->cacheArchivo.contCache[tam].contenido,0,1024);
				}

	}
	(void) rutaArchivo;
	(void) fi;
	(void)data;

	return 0;
}

/*____________________________________________________*/

int FS_release(const char *ruta, struct fuse_file_info *fi){
    (void) ruta;
    (void) fi;
	free((datosArchivo*) ((long)(fi->fh)));
	return 0;
}

/*____________________________________________________*/

int FS_truncate(const char *rutaArchivo, off_t offset){

	int indice,tamanio;
		float resultado;

		datosArchivo* data=NULL;
		data=malloc(sizeof(datosArchivo));
		char*ruta=malloc(strlen(rutaArchivo)+1);
		data->lista=malloc(sizeof(listaClusters));
				data->lista->numCluster=0;

			strncpy(ruta,rutaArchivo,strlen(rutaArchivo));
		ruta[strlen(rutaArchivo)]='\0';


			resultado=buscarArchivo(ruta,data);
		if(resultado!=0){
			free(data);free(ruta);
			return resultado;
		}


		if(data->numCluster==0){
				int numCluster=0;
				down(mutexFAT);
				if(numClustersLibres>=1){
					up(mutexFAT);

				int rIO= buscar_Clusters_libres(1,&numCluster);

				if(rIO!=0){
					return -EIO;
				}
				else{
					data->numCluster=numCluster;
					grabar_FAT(data->numCluster,0xFFFFFFF);
				}
			}
						 else{
							 up(mutexFAT);
							 return -ENOSPC;
						 }

				char bufferEscritura[1024];

				realizar_pedido_lectura(data->sectorEntrada/2,bufferEscritura);
				if(data->sectorEntrada>data->sectorEntrada/2+data->sectorEntrada/2)
					data->offset+=512;
				if(data->longfn==1){
					char vecAux[4];

					memset(vecAux,0,4);

					memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
					memcpy(bufferEscritura+data->offset+32+0x1A,vecAux,sizeof(uint16_t));
					memcpy(bufferEscritura+data->offset+32+0x14,vecAux+2,sizeof(uint16_t));

				}
				else{
					char vecAux[4];

					memset(vecAux,0,4);

					memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
					memcpy(bufferEscritura+data->offset+0x1A,vecAux,sizeof(uint16_t));
					memcpy(bufferEscritura+data->offset+0x14,vecAux+2,sizeof(uint16_t));

							  			}
					realizar_pedido_escritura(data->sectorEntrada/2,bufferEscritura);
					int clus=data->numCluster;
					agregarCluster(&clus,data->lista);
		data->cantClusters=1;
			}




	if(data->tamanioArchivo==0 && offset==0)
		return 0;

	char bufferEscritura[1024];

			realizar_pedido_lectura(data->sectorEntrada/2,bufferEscritura);
			if(data->sectorEntrada>data->sectorEntrada/2+data->sectorEntrada/2)
				data->offset+=512;

			if(data->longfn==1){
				char vecAux[4];

				memset(vecAux,0,4);

				memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
				memcpy(bufferEscritura+data->offset+32+0x1A,vecAux,sizeof(uint16_t));
				memcpy(bufferEscritura+data->offset+32+0x14,vecAux+2,sizeof(uint16_t));

			}
			else{
				char vecAux[4];

				memset(vecAux,0,4);

				memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
				memcpy(bufferEscritura+data->offset+0x1A,vecAux,sizeof(uint16_t));
				memcpy(bufferEscritura+data->offset+0x14,vecAux+2,sizeof(uint16_t));

						  			}
				realizar_pedido_escritura(data->sectorEntrada/2,bufferEscritura);
		data->lista=malloc(sizeof(listaClusters));
		data->lista->numCluster=0;
		data->cantClusters=conseguirCadenaClusters(data->lista,data->numCluster);
	if(offset>data->tamanioArchivo){
			char* vector=malloc(offset-data->tamanioArchivo);
		memset(vector,0,offset-data->tamanioArchivo);
			escribirArchivo(ruta,data,vector,data->tamanioArchivo,offset-data->tamanioArchivo);
			free(vector);

			return 0;
		}
	else{
		resultado=(offset/512)/8;


			grabarEntradaArchivo(ruta,offset);
					for(indice=0;indice<=resultado;indice++)
						data->lista=data->lista->sig;
					if(data->lista!=NULL){
						if(offset!=0)
							grabar_FAT(data->lista->numCluster,0xFFFFFFF);
						else{
							char bufferEscritura[1024];
							data->numCluster=0;
							grabar_FAT(data->lista->numCluster,0x0000000);
									realizar_pedido_lectura(data->sectorEntrada/2,bufferEscritura);
									if(data->sectorEntrada>data->sectorEntrada/2+data->sectorEntrada/2)
										data->offset+=512;
									if(data->longfn==1){
										char vecAux[4];

										memset(vecAux,0,4);

										memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
										memcpy(bufferEscritura+data->offset+32+0x1A,vecAux,sizeof(uint16_t));
										memcpy(bufferEscritura+data->offset+32+0x14,vecAux+2,sizeof(uint16_t));

									}
									else{
										char vecAux[4];
int num=0;
										memset(vecAux,0,4);

										memcpy(vecAux,&num,sizeof(uint32_t));
										memcpy(bufferEscritura+data->offset+0x1A,vecAux,sizeof(uint16_t));
										memcpy(bufferEscritura+data->offset+0x14,vecAux+2,sizeof(uint16_t));

												  			}
										realizar_pedido_escritura(data->sectorEntrada/2,bufferEscritura);
										int clus=data->numCluster;
							setSector(data->lista->numCluster,0);

						}
						data->lista=data->lista->sig;
					while(data->lista!=NULL){
						grabar_FAT(data->lista->numCluster,0x0000000);
						setSector(data->lista->numCluster,0);
						data->lista=data->lista->sig;
					}
					bajarBitVector();
				}
					free(data->lista);
					free(data);

				free(ruta);

			}

		return 0;

	}


/*____________________________________________________*/

int FS_unlink(const char *path){
	int resultado;
		datosArchivo* data=NULL;
		data=malloc(sizeof(datosArchivo));

		listaClusters* cadenaClusters=NULL;
		cadenaClusters=malloc(sizeof(listaClusters));
		cadenaClusters->numCluster=0;
		char*ruta=malloc(strlen(path)+1);


			strncpy(ruta,path,strlen(path));
		ruta[strlen(path)]='\0';
			resultado=buscarArchivo(ruta,data);
		if(resultado!=0){
			free(ruta);
			return (-ENOENT);
		}
		resultado=borrarEntradaDir(ruta);
		if(resultado==0){
			conseguirCadenaClusters(cadenaClusters,data->numCluster);
			while(cadenaClusters!=NULL){
				grabar_FAT(cadenaClusters->numCluster,0x0000000);
				setSector(cadenaClusters->numCluster,0);
				cadenaClusters=cadenaClusters->sig;
			}
			bajarBitVector();
			free(data);
			free(cadenaClusters);
			free(ruta);
			return 0;

		}
		else{
			free(data);
			free(cadenaClusters);
			free(ruta);
			return resultado;
		}
}

/*____________________________________________________*/

int FS_mkdir(const char *rutaArchivo, mode_t mode){

		int resultado=1;
		datosArchivo* data;
		data=malloc(sizeof(datosArchivo));
		data->tipo=DIRECTORIO;
		data->tamanioArchivo=0;
		data->numCluster=0;
			
		char*ruta=malloc(strlen(rutaArchivo)+1);

		strncpy(ruta,rutaArchivo,strlen(rutaArchivo));
		ruta[strlen(rutaArchivo)]='\0';
		resultado=buscarArchivo(ruta,data);
		if(resultado!=0 ){
			crearArchivoDirectorio(ruta,data,mode,1);
			free(ruta);
			return 0;
		}
		else{
			free(ruta);
			return (-EEXIST); //el dir ya existe
		}
}

/*____________________________________________________*/

int FS_readdir(const char *path, void *buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi){

    (void) offset;
    (void) fi;

    fat32_directory *ptr, *directorio;
   	datosArchivo*data;   
	char*ruta=malloc(strlen(path)+1);
	directorio=malloc(sizeof(fat32_directory));
    data=malloc(sizeof(datosArchivo));
    data->tipo=DIRECTORIO;
    data->tamanioArchivo=0;
	directorio->tipo=0;

    strcpy(ruta,path);
    ruta[strlen(path)]='\0';
    if(strcmp(path,"/")!=0){
    	if(buscarArchivo(ruta,data)!=0){
    		free(data);
    		free(ruta);
    		return (-ENOENT);
    	}
    }
    else
    	data->numCluster=2;

   leerDirectorio(directorio,data->numCluster);
   ptr=directorio;

   filler(buffer, ".", NULL, 0);
   filler(buffer, "..", NULL, 0);

   while (ptr != NULL&&ptr->tipo !=0) {
	   int i;
	   for(i=0;i<strlen(ptr->nombre)&& (ptr->nombre[i]!=' ');i++);
	   	   if(i<strlen(ptr->nombre))
	   		   ptr->nombre[i]='.';
        filler(buffer,ptr->nombre, NULL, 0);
        ptr=ptr->sig;
    }
  
   free(data);
   free(ruta);

   return 0;
}

/*____________________________________________________*/

int FS_rmdir(const char *path){
	char buffer[1024];
	datosArchivo* data=NULL;
	int resultado;
	data=malloc(sizeof(datosArchivo));
	
	char*ruta=malloc(strlen(path)+1);
	
	strncpy(ruta,path,strlen(path));
	ruta[strlen(path)]='\0';
		
	resultado=buscarArchivo(ruta,data);

	if(resultado!=0){
		free(data);
		free(ruta);
		return (-ENOENT);
	};
	int sector=(calcularPrimerSectorDelCluster(data->numCluster));
	memset(buffer,0,1024);
	realizar_pedido_lectura(sector/2,buffer);
	int offs=0;
	uint8_t entrada;
	if(sector>sector/2+sector/2)
		offs+=512;
	memcpy(&entrada,buffer+64+offs,sizeof(uint8_t));

	if((entrada!=0xE5)&&(entrada!=0x00)) //32 para . 32 para ..
		return (-EPERM); //tiene datos dentro
	else{
		listaClusters* cadenaClusters=NULL;
		cadenaClusters=malloc(sizeof(listaClusters));
		cadenaClusters->numCluster=0;
		resultado=borrarEntradaDir(ruta);
		if(resultado==0){
			conseguirCadenaClusters(cadenaClusters,data->numCluster);
			while(cadenaClusters!=NULL){
				grabar_FAT(cadenaClusters->numCluster,0x0000000);
				setSector(cadenaClusters->numCluster,0);
				cadenaClusters=cadenaClusters->sig;
			}
			bajarBitVector();
			free(data);
			free(cadenaClusters);
			free(ruta);
			return 0;
		}
		else{
			free(data);
			free(cadenaClusters);
			free(ruta);
			return resultado;
		}
	}
}

/*____________________________________________________*/

int FS_getattr(const char *rutaArchivo, struct stat *statbuffer){

	int resultado = 0;
	datosArchivo* data=malloc(sizeof(datosArchivo));
	char*ruta=malloc(strlen(rutaArchivo)+1);
	memset(statbuffer, 0, sizeof(struct stat));
	
	strncpy(ruta,rutaArchivo,strlen(rutaArchivo));
	ruta[strlen(rutaArchivo)]='\0';
		
	if(strcmp(rutaArchivo,"/")==0){
		statbuffer->st_mode = S_IFDIR | 0777;
		statbuffer->st_nlink = 2;
		return 0;
	}

	
	else{
		if(rutaArchivo[0]=='.')
			return (-ENOENT);
		data->numCluster=0;
		resultado=buscarArchivo(ruta,data);
		if((resultado)==0) {
			if(data->tipo==DIRECTORIO){
				statbuffer->st_mode = S_IFDIR | 0777;
				statbuffer->st_nlink = 2;
				return resultado;

			}
			else if (data->tipo==ARCHIVO){
				statbuffer->st_mode = S_IFREG | 0777;
				statbuffer->st_nlink = 1;
				statbuffer->st_size = data->tamanioArchivo;
				statbuffer->st_blocks=data->tamanioArchivo /1024;
				statbuffer->st_blksize= 1024;
				free(ruta);
				return resultado;
			}
			else
				return (-ENOENT);

		}
		else if (resultado==3){
			return (-ENOENT);
		}
		else{
			resultado = (-ENOENT);
			free(ruta);
			return resultado;
	  }

	}

}

/*____________________________________________________*/

int FS_rename(const char *pathActual, const char *nuevoPath){

	datosArchivo* data=NULL;
	int resultado;

	data=malloc(sizeof(datosArchivo));
	if(!strcmp(pathActual,nuevoPath))
		return (-1);
	char*ruta=malloc(strlen(pathActual)+1);
	strncpy(ruta,pathActual,strlen(pathActual));
	ruta[strlen(pathActual)]='\0';
	resultado=buscarArchivo(ruta,data);
	if(resultado!=0){
		free(ruta);
		return resultado;
	}
	else{
		char*ruta2=malloc(strlen(nuevoPath)+1);
		strncpy(ruta2,nuevoPath,strlen(nuevoPath));
		ruta2[strlen(nuevoPath)]='\0';

		crearArchivoDirectorio(ruta2,data,1,2);
		resultado= borrarEntradaDir(ruta);

		free(ruta);
		free(ruta2);
		if(resultado!=0)
			return resultado;
		else
			return 0;
	}
}

/*____________________________________________________*/

int FS_fgetattr(const char *rutaArchivo, struct stat *statbuffer){
return  (FS_getattr(rutaArchivo,statbuffer));
}

